﻿// sdss_mysql_2017.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "strptime.h"

#include <windows.h>
#include <thread>
#include <mutex>
//#include "include\pthread.h"
//#pragma comment(lib, "pthreadVC2.lib")
//#include <pthread.h>
/* Standard C++ includes */
#include <stdlib.h>
#include <iostream>
#include <fstream>

#include <set>
#include <string>
#include <random>
#include <regex>
/*
Include directly the different
headers from cppconn/ and mysql_driver.h + mysql_util.h
(and mysql_connection.h). This will reduce your build time!
*/
#include "mysql_connection.h"

#include "cppconn/driver.h"
#include "cppconn/exception.h"
#include "cppconn/resultset.h"
#include "cppconn/statement.h"
#include "boost/bind.hpp"
#include "boost/ref.hpp"
#include "boost/algorithm/string.hpp"
#include "boost/date_time/gregorian/gregorian.hpp"
#include "boost/accumulators/accumulators.hpp"
#include "boost/accumulators/statistics/stats.hpp"
#include "boost/accumulators/statistics/mean.hpp"
#include "boost/accumulators/statistics/variance.hpp"
#include <boost/functional/hash.hpp>
#include <boost/range/algorithm/count.hpp>
#include <boost/regex.hpp>
#include <boost/algorithm/string/regex.hpp>

using namespace std;

//time_t stringToDatetime(string str);
double selected_column_score(string s1, string s2);
double table_source_score(string s1, bool &isWhere1, bool &isGroup1, string s2, bool &isWhere2, bool&isGroup2);
double predicate_score(string s1, bool &isWhere1, string s2, bool &isWhere2, int &parameter_score);
double misc_score(string s1, bool isGroup1, string s2, bool isGroup2);
void remove_table_alias(string &s);
void replace_comma_with_dollar(string &s);


bool is_number(const std::string &s) {
	return !s.empty() && all_of(s.begin(), s.end(), ::isdigit);
}

void trim_and_reduce_spaces(string& s)
{
	boost::trim(s);
	boost::regex e("(\\n|\\t)");
	s = boost::regex_replace(s, e, " ");
	while (s.find("  ") != s.npos)
		boost::replace_all(s, "  ", " ");
	return;
}

static ifstream fin("input_ip.txt", std::ios::in);
static ofstream fout("output.txt");
mutex mtx;

//struct st_worker_thread_param {
//	sql::Driver *driver;
//	sql::Connection *con;
//};

int main(void)
{
	//	string s1 = "SELECT TOP 10 fld.run, fld.avg_sky_muJy, fld.runarea AS area, ISNULL(fp.nfirstmatch, 0) \
	//\
	//		FROM(\
	//\
	//			SELECT run, sum(primaryArea) AS runarea,\
	//\
	//			3631e6*avg(power(cast(10. as float), -0.4*sky_r)) as avg_sky_muJy\
	//\
	//			FROM Field\
	//\
	//			GROUP BY run\
	//\
	//		) AS fld\
	//\
	//		INNER JOIN(\
	//\
	//			SELECT p.run, count(*) AS nfirstmatch\
	//\
	//			FROM FIRST AS fm\
	//\
	//			INNER JOIN photoprimary as p\
	//\
	//			ON p.objid = fm.objid\
	//\
	//			GROUP BY p.run\
	//\
	//		) AS fp\
	//\
	//		ON fld.run = fp.run\
	//\
	//		ORDER BY fld.run ";
	//	string s2 = "SELECT TOP 500000 p.objid,\
	//\
	//		p.run, p.rerun, p.camcol, p.field, p.obj,\
	//\
	//		p.type, p.ra, p.dec, p.u, p.g, p.r, p.i, p.z,\
	//\
	//		p.Err_u, p.Err_g, p.Err_r, p.Err_i, p.Err_z\
	//\
	//		FROM fGetNearbyObjEq(7.83212349723884, 7.41487690161025, 10) n, PhotoPrimary p\
	//\
	//		WHERE n.objID = p.objID AND p.g between 0 AND 19";
	//	boost::algorithm::to_lower(s1);
	//	boost::algorithm::to_lower(s2);
	//	int pos = -1;
	//	if ((pos = s1.find("order by")) != -1)
	//		s1 = s1.substr(0, pos-1);
	// 	trim_and_reduce_spaces(s1);
	//	trim_and_reduce_spaces(s2);
	//	remove_table_alias(s1);
	//	remove_table_alias(s2);
	//	replace_comma_with_dollar(s1);
	//	replace_comma_with_dollar(s2);
	//	selected_column_score(s1, s2);
	//	bool isWhere1 = true, isWhere2 = true;
	//	table_source_score(s1, isWhere1, s2, isWhere2);
	//	predicate_score(s1, isWhere1, s2, isWhere2);
	//	set<string> sip;
	try {
		sql::Driver *driver;
		/* Create a connection */
		driver = get_driver_instance();
		//res = stmt->executeQuery("SELECT clientIP FROM sqllog");

		//ofstream file_ip("output_ip.txt");
		////long tick = 1;
		//while (res->next()) {
		//	/* Access column data by alias or column name */
		//	string s = res->getString("clientIP").c_str();
		//	if (sip.insert(s).second)
		//		file_ip << s << endl;
		//}

		//long count = sip.size();
		//file_ip.close();
		//	// Random seed
		//	random_device rd;
		//	// Initialize Mersenne Twister pseudo-random number generator
		//	mt19937 gen(rd());
		//	// Generate pseudo-random numbers
		//	// uniformly distributed in range (1, count)
		//	uniform_int_distribution<> dis(1, count);

		//	string* s = new string[100];
		//	// Generate ten pseudo-random numbers
		//	for (int i = 0; i < 100; i++)
		//	{
		//		long num = dis(gen);
		//		std::set<std::string>::iterator it = std::next(sip.begin(), num);
		//		s[i] = *it;
		//		cout << *it << endl;
		//	}
		//	string* s = new string[110];
		//	int tick = 0;
		//	std::ifstream fin("input.txt", std::ios::in);
		//	char line[20] = { 0 };

		//	while (fin.getline(line, sizeof(line)))
		//		s[tick++] = line;

		//	fin.clear();
		//	fin.close();


		//std::set<string>::iterator it;
		//for (it = sip.begin(); it != sip.end(); ++it)
		//res = stmt->executeQuery("ALTER TABLE sqllog ADD INDEX(clientIP)");
		fout << "CLIENTIP STAT_COUNT AVG_INTERVAL VAR_INTERVAL AVG_ELAPSED SELECTED_COL_SCORE TLB_SOURCE_SCORE PREDICATE_SCORE MISC_SCORE" << endl;
		//int n = thread::hardware_concurrency();
		HANDLE evt[4];
		vector<thread> threads;
		for (int i = 0; i < 4; ++i) {
			evt[i] = ::CreateEvent(NULL, false, false, NULL);
			/*pthread_t pt;
			struct st_worker_thread_param *param = new st_worker_thread_param;
			param->driver = driver;
			param->con = con.get();
			pthread_create(&pt, NULL, thread_proc, (void *)param);
			pthread_join(pt, NULL);*/
			thread t([&]() {
				driver->threadInit();

				std::auto_ptr< sql::Connection > con;
				std::auto_ptr< sql::Statement > stmt;
				std::auto_ptr< sql::ResultSet > res;
				con.reset(driver->connect("tcp://127.0.0.1:3306", "root", "root"));
				con->setSchema("sdss");
				char line[256] = { 0 };
				stmt.reset(con->createStatement());
				while (fin.getline(line, sizeof(line)))
				{
					// Retrieve all the statements from one session ordered by execution time.
					string sql = "SELECT * FROM sqllog WHERE clientIP='" + string(line) + "' ORDER BY STR_TO_DATE(thetime, '%m/%d/%Y %r')";
					mtx.lock();
					cout << "Thread " << ::this_thread::get_id() << " executes query:" << endl;
					cout << sql << endl;
					mtx.unlock();
					res.reset(stmt->executeQuery(sql.c_str()));

					mtx.lock();
					res->last();
					int count = res->getRow();
					cout << "Thread " << ::this_thread::get_id() << " " << string(line) << " :" << count << " statements in totoal..."<<endl;
					res->beforeFirst();
					mtx.unlock();

					unsigned int metric1 = 0;
					double metric2 = 0, metric3 = 0, metric4 = 0, metric5 = 0, metric6 = 0, metric7_part1 = 0, metric7_part2 = 0, metric7 = 0, metric8 = 0;
					time_t tf = NULL, tl = NULL;
					string sf, sl;
					vector<string> vs;
					vector<double> vi;
					vector<double> ve;
					vector<tm> time;
					while (res->next()) {
						string statement = res->getString("statement").c_str();
						/*
						*********************Format statement************************
						#1 lower all the characters
						#2 ignore all non-sql statements （exclude Data Control Language statement and non-SQL statement)
						#3 trim begin end end space characters and remove multiple sequence space characters
						#4 remove all table alias
						#5 replace comma with dollar symbol, in order to split easily.
						*/
						// #1
						boost::algorithm::to_lower(statement);
						int pos = -1;
						if ((pos = statement.find("order by")) != -1)
							statement = statement.substr(0, pos - 1);
						// #2
						if ((statement.find("create table") != -1) || (statement.find("select") == -1) || (statement.find("from") == -1) || (statement.find("<a target") != -1)) continue;
						// #3
						trim_and_reduce_spaces(statement);
						// #4
						remove_table_alias(statement);
						// #5
						replace_comma_with_dollar(statement);

						struct tm t, t_start;
						string time = res->getString("theTime").c_str();
						//boost::gregorian::date d = boost::gregorian::;
						if (strptime(time.c_str(), "%m/%d/%Y %I:%M:%S %p", &t) == NULL)
							printf("strptime ERROR!\n");
						// Record the first statement of this session
						if (vs.empty()) t_start = t;

						// Compare the time difference and separate into different session if the difference greater than 8h 
						if (mktime(&t) - mktime(&t_start) > 3600 * 8) {
							boost::accumulators::accumulator_set<double, boost::accumulators::stats<boost::accumulators::tag::variance> > acc;
							for_each(vi.begin(), vi.end(), bind<void>(ref(acc), _1));
							metric2 = boost::accumulators::mean(acc);
							metric3 = boost::accumulators::variance(acc);

							boost::accumulators::accumulator_set<double, boost::accumulators::stats<boost::accumulators::tag::mean> > acc1;
							for_each(ve.begin(), ve.end(), bind<void>(ref(acc1), _1));
							metric4 = boost::accumulators::mean(acc1);

							if (metric1 != 0) metric7 = metric7_part1 + metric7_part2 / metric1;
							mtx.lock();
							count -= metric1;
							cout << "Thread " << ::this_thread::get_id() << " :" << count << " statements remained to be processing..." << endl;
							fout << line << " " << metric1 << " " << metric2 << " " << metric3 << " " << metric4 << " " << metric5 << " " << metric6 << " " << metric7 << " " << metric8 << " " << endl;
							mtx.unlock();
							// Restore all the values to be the initial state.
							metric1 = 0; metric2 = 0; metric4 = 0; metric5 = 0; metric6 = 0; metric7 = 0; metric8 = 0;
							vs.clear(); vi.clear(); ve.clear();

							string elapsed = res->getString("elapsed").c_str();
							ve.push_back(boost::lexical_cast<double>(elapsed));

							t_start = t;
							tl == NULL;
							tf = mktime(&t);
							sf = statement;
						}
						else {
							string elapsed = res->getString("elapsed").c_str();
							ve.push_back(boost::lexical_cast<double>(elapsed));

							if (vs.empty()) {
								tf = mktime(&t);
								sf = statement;
							}
							else if (tl == NULL) {
								tl = mktime(&t);
								sl = statement;

								vi.push_back(tl - tf);
								metric5 += selected_column_score(sf, sl);
								bool isWhere1 = true, isWhere2 = true;
								bool isGroup1 = false, isGroup2 = false;
								metric6 += table_source_score(sf, isWhere1, isGroup1, sl, isWhere2, isGroup2);
								int parameter_score = 0;
								metric7_part1 += predicate_score(sf, isWhere1, sl, isWhere2, parameter_score);
								metric7_part2 += parameter_score;
								metric8 += misc_score(sf, isGroup1, sl, isGroup2);
							}
							else {
								tf = tl;
								tl = mktime(&t);
								sf = sl;
								sl = statement;

								vi.push_back(tl - tf);
								metric5 += selected_column_score(sf, sl);
								bool isWhere1 = true, isWhere2 = true;
								bool isGroup1 = false, isGroup2 = false;
								metric6 += table_source_score(sf, isWhere1, isGroup1, sl, isWhere2, isGroup2);
								int parameter_score = 0;
								metric7_part1 += predicate_score(sf, isWhere1, sl, isWhere2, parameter_score);
								metric7_part2 += parameter_score;
								metric8 += misc_score(sf, isGroup1, sl, isGroup2);
							}
						}
						metric1++;
						vs.push_back(statement);
					}
					boost::accumulators::accumulator_set<double, boost::accumulators::stats<boost::accumulators::tag::variance> > acc;
					for_each(vi.begin(), vi.end(), bind<void>(ref(acc), _1));
					metric2 = boost::accumulators::mean(acc);
					metric3 = boost::accumulators::variance(acc);

					boost::accumulators::accumulator_set<double, boost::accumulators::stats<boost::accumulators::tag::variance> > acc1;
					for_each(ve.begin(), ve.end(), bind<void>(ref(acc1), _1));
					metric4 = boost::accumulators::mean(acc1);
					if (metric1 != 0) metric7 = metric7_part1 + metric7_part2 / metric1;
					mtx.lock();
					fout << line << " " << metric1 << " " << metric2 << " " << metric3 << " " << metric4 << " " << metric5 << " " << metric6 << " " << metric7 << " " << metric8 << " " << endl;
					mtx.unlock();
				}
				driver->threadEnd();
				::SetEvent(evt[i]);
			});
			t.detach();
		}
		/*for (auto& thread : threads) {
			thread.join();
		}*/
		::WaitForMultipleObjects(4, evt, true, INFINITE);
		fin.close();
		fout.close();
	}
	catch (sql::SQLException &e) {
		cout << "# ERR: SQLException in " << __FILE__;
		cout << "(" << __FUNCTION__ << ") on line "
			<< __LINE__ << endl;
		cout << "# ERR: " << e.what();
		cout << " (MySQL error code: " << e.getErrorCode();
		cout << ", SQLState: " << e.getSQLState() << " )" << endl;
	}
	return EXIT_SUCCESS;
}

void replace_comma_with_dollar(string &s)
{
	int flag = 0;
	int len = s.length();

	for (int i = 0; i < len; i++)
	{
		if (s[i] == '(') flag++;
		else if (s[i] == ')') flag--;
		else if (flag == 0 && s[i] == ',')
		{
			s[i] = '$';
		}
	}
}

void remove_table_alias(string &s)
{
	// Using rgular expression to remove "ALIAS." and " ALIAS" pattern
	boost::regex e("[a-zA-Z_]+[.]");
	// Repeated search and traverse every ailas until completed.
	boost::smatch sm;
	while (boost::regex_search(s, sm, e))
	{
		string alias(sm.str(), 0, sm.str().length() - 1);
		boost::regex e(alias + "[.]");
		s = boost::regex_replace(s, e, "");
		string se = "(\\sas)?(\\s" + alias + ")([^a-zA-Z_.])";
		boost::regex e1(se);
		s = boost::regex_replace(s, e1, "$3");
	}
	// Using rgular expression to remove unused " AS ALIAS" pattern
	boost::regex e1("\\bas\\s[a-zA-Z_]+\\b");
	s = boost::regex_replace(s, e1, "");
}

double selected_column_score(string s1, string s2)
{
	string str1, str2;
	boost::regex e("(?<=select)(\\stop\\s\\d*)?.*?(?=\\sfrom)");
	boost::regex e1("(top\\s\\d+)(.*)");
	boost::smatch sm;
	if (boost::regex_search(s1, sm, e)) str1 = sm[0];
	if (str1.find("top") != -1) str1 = boost::regex_replace(str1, e1, "$2");

	if (boost::regex_search(s2, sm, e)) str2 = sm[0];
	if (str2.find("top") != -1) str2 = boost::regex_replace(str2, e1, "$2");
	vector<string> splitVec1, splitVec2;
	boost::algorithm::split(splitVec1, str1, boost::algorithm::is_any_of("$"), boost::algorithm::token_compress_on);
	boost::algorithm::split(splitVec2, str2, boost::algorithm::is_any_of("$"), boost::algorithm::token_compress_on);

	vector<string>::iterator iter = splitVec1.begin();
	set<string> columns_set;
	/*boost::hash<string> string_hash;
	size_t hash = string_hash(*iter);*/
	while (iter != splitVec1.end()) {
		columns_set.insert(*iter);
		++iter;
	}
	unsigned int intersection_size = 0;
	iter = splitVec2.begin();
	while (iter != splitVec2.end()) {
		if (columns_set.insert(*iter).second == false) intersection_size++;
		++iter;
	}

	return columns_set.size() - intersection_size;
}

double table_source_score(string s1, bool &isWhere1, bool &isGroup1, string s2, bool &isWhere2, bool&isGroup2)
{
	int len1 = s1.length();
	int len2 = s2.length();
	int start_pos, start_pos1, end_pos = 0, end_pos1 = 0;
	start_pos = s1.find("from");
	start_pos1 = s2.find("from");
	// Retrieve the FROM clause from SQL statement
	int flag = 0;
	for (int i = start_pos + 4; i < len1; i++) {
		if (s1[i] == '(') flag++;
		else if (s1[i] == ')') flag--;
		else {
			if (flag == 0 && s1[i] == 'w') {
				if (i + 4 < len1 && s1[i + 1] == 'h'&& s1[i + 2] == 'e' &&s1[i + 3] == 'r' && s1[i + 4] == 'e') {
					end_pos = i - 1;
					break;
				}
			}
			else if (flag == 0 && s1[i] == 'g') {
				if (i + 4 < len1 && s1[i + 1] == 'r'&& s1[i + 2] == 'o' && s1[i + 3] == 'u' && s1[i + 4] == 'p') {
					isGroup1 = true;
					end_pos = i - 1;
					break;
				}
			}
		}
	}
	if (end_pos == 0) {
		end_pos = len1 - 1;
		isWhere1 = false;
	}

	for (int i = start_pos1 + 4; i < len2; i++) {
		if (s2[i] == '(') flag++;
		else if (s2[i] == ')') flag--;
		else {
			if (flag == 0 && s2[i] == 'w') {
				if (i + 4 < len2 && s2[i + 1] == 'h'&& s2[i + 2] == 'e' && s2[i + 3] == 'r' && s2[i + 4] == 'e') {
					end_pos1 = i - 1;
					break;
				}
			}
			else if (flag == 0 && s2[i] == 'g') {
				if (i + 4 < len2 && s2[i + 1] == 'r'&& s2[i + 2] == 'o' && s2[i + 3] == 'u' && s2[i + 4] == 'p') {
					isGroup2 = true;
					end_pos1 = i - 1;
					break;
				}
			}
		}
	}
	if (end_pos1 == 0) {
		end_pos1 = len2 - 1;
		isWhere2 = false;
	}
	string str1(s1, start_pos + 4, end_pos - start_pos - 3);
	string str2(s2, start_pos1 + 4, end_pos1 - start_pos1 - 3);

	boost::regex e("(left outer|left|right outer|right|inner|full)?(\\sjoin)(.*)");
	if (str1.find("join") != -1) str1 = boost::regex_replace(str1, e, "$ $3");
	if (str2.find("join") != -1) str2 = boost::regex_replace(str2, e, "$ $3");

	vector<string> splitVec1, splitVec2;
	boost::algorithm::split(splitVec1, str1, boost::algorithm::is_any_of("$"), boost::algorithm::token_compress_on);
	boost::algorithm::split(splitVec2, str2, boost::algorithm::is_any_of("$"), boost::algorithm::token_compress_on);

	vector<string>::iterator iter = splitVec1.begin();
	set<string> tables_set;
	while (iter != splitVec1.end()) {
		tables_set.insert(*iter);
		++iter;
	}
	unsigned int intersection_size = 0;
	iter = splitVec2.begin();
	while (iter != splitVec2.end()) {
		if (tables_set.insert(*iter).second == false) intersection_size++;
		++iter;
	}

	return tables_set.size() - intersection_size;
}

double predicate_score(string s1, bool &isWhere1, string s2, bool &isWhere2, int &parameter_score)
{
	map<string, string> map1;
	map<string, string> map2;
	map1.clear();
	map2.clear();

	if (isWhere1) {
		int len1 = s1.length();
		int start_pos, end_pos = 0;
		start_pos = s1.rfind("where");
		int pos = -1;
		if ((pos = s1.rfind("group")) > start_pos) end_pos = pos - 1;
		else end_pos = len1 - 1;

		string str1(s1, start_pos + 5, end_pos - start_pos - 4);
		boost::regex e("(between[0-9\\.\\s]*)(and)");
		str1 = boost::regex_replace(str1, e, "$1AND");
		vector<string> splitVec1;
		boost::algorithm::split_regex(splitVec1, str1, boost::regex("and"));

		vector<string>::iterator iter = splitVec1.begin();
		boost::regex e1("(=|between|<|<=|>|>=|!=)");
		while (iter != splitVec1.end()) {
			string s = *iter;
			boost::trim(s);
			if (s[0] == '(' && s[s.length() - 1] == ')')
				s = s.substr(1, s.length() - 2);
			vector<string> v;
			boost::algorithm::split_regex(v, s, e1);
			if (v.size() > 1) {
				string s1 = v.at(0);
				string s2 = v.at(1);
				boost::trim(s1); boost::trim(s2);
				map1.insert(pair<string, string>(s1, s2));
			}
			iter++;
		}

	}
	if (isWhere2) {
		int len2 = s2.length();
		int start_pos1, end_pos1;
		start_pos1 = s2.rfind("where");
		int pos = -1;
		if ((pos = s2.rfind("group")) > start_pos1) end_pos1 = pos - 1;
		else end_pos1 = len2 - 1;

		string str2(s2, start_pos1 + 5, end_pos1 - start_pos1 - 4);
		boost::regex e("(between[0-9\\.\\s]*)(and)");
		str2 = boost::regex_replace(str2, e, "$1AND");
		vector<string> splitVec2;
		boost::algorithm::split_regex(splitVec2, str2, boost::regex("and"));

		vector<string>::iterator iter = splitVec2.begin();
		boost::regex e1("(=|between|<|<=|>|>=|!=)");
		while (iter != splitVec2.end()) {
			string s = *iter;
			boost::trim(s);
			if (s[0] == '(' && s[s.length() - 1] == ')')
				s = s.substr(1, s.length() - 2);
			vector<string> v;
			boost::algorithm::split_regex(v, s, e1);
			if (v.size() > 1) {
				string s1 = v.at(0);
				string s2 = v.at(1);
				boost::trim(s1); boost::trim(s2);
				map2.insert(pair<string, string>(s1, s2));
			}
			iter++;
		}
	}
	set<string> predicates_set;
	for (map<string, string>::iterator iter = map1.begin(); iter != map1.end(); iter++) predicates_set.insert(iter->first);
	unsigned int intersection_size = 0;
	for (map<string, string>::iterator iter = map2.begin(); iter != map2.end(); iter++) {
		string spre = iter->first;
		if (predicates_set.insert(spre).second == false) {
			intersection_size++;
			// Compare if the parameter is different
			if ((map1.find(spre))->second != iter->second) parameter_score++;
		}
	}
	return predicates_set.size() - intersection_size;
}

double misc_score(string s1, bool isGroup1, string s2, bool isGroup2)
{
	if (!isGroup1 && !isGroup2) return 0;
	if (isGroup1^isGroup2) return 1;
	else {
		int pos, pos1;
		pos = s1.rfind("group by") + 9;
		pos1 = s2.rfind("group by") + 9;
		string str1 = s1.substr(pos, s1.length() - pos + 1);
		string str2 = s2.substr(pos1, s2.length() - pos1 + 1);
		if (str1 != str2) return 0.5;
	}
	return 0;
}

//time_t stringToDatetime(string str)
//{
//	char *cha = (char*)str.data();             // 将string转换成char*。
//	tm tm_;                                    // 定义tm结构体。
//	int year, month, day, hour, minute, second;// 定义时间的各个int临时变量。
//	sscanf_s(cha, "%d/%d/%d %d:%d:%d", &month, &day, &year, &hour, &minute, &second);// 将string存储的日期时间，转换为int临时变量。
//	tm_.tm_year = year - 1900;                 // 年，由于tm结构体存储的是从1900年开始的时间，所以tm_year为int临时变量减去1900。
//	tm_.tm_mon = month - 1;                    // 月，由于tm结构体的月份存储范围为0-11，所以tm_mon为int临时变量减去1。
//	tm_.tm_mday = day;                         // 日。
//	tm_.tm_hour = hour;                        // 时。
//	tm_.tm_min = minute;                       // 分。
//	tm_.tm_sec = second;                       // 秒。
//	tm_.tm_isdst = 0;                          // 非夏令时。
//	time_t t_ = mktime(&tm_);                  // 将tm结构体转换成time_t格式。
//	return t_;                                 // 返回值。 
//}